package com.rongji.cms.tools.db.utils;

import com.rongji.cms.tools.db.constant.DbConstant;
import com.rongji.cms.tools.db.domain.vo.DbInfoVo;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

/**
 * @author yang
 * @date 2023/1/29 9:03
 * @description 数据库信息相关
 */

@Slf4j
public class DbUtil {

    /**
     * 为了学习Function用的，这里没啥必要
     * 统一执行function的apply方法，省的每个策略类都写一遍
     * @param function
     * @return
     */
    public static String getConnUrl(Function<StringBuilder,String> function){
        StringBuilder sb=new StringBuilder();

        return function.apply(sb);
    }

    /**
     * 拼凑出完整的查询语句
     * select * from user_tab_cols where TABLE_NAME = 'CMS_CATALOG';
     * @param preTabColumnSql
     * @param tableName
     * @return
     */
    private static String getColumnsSQL(String preTabColumnSql, String tableName) {
        String sql= preTabColumnSql+tableName+"'";
        return sql;
    }


    /**
     * 获取连接
     * @param driverName
     * @param dbInfoVo
     * @param url
     * @return
     */
    public static Connection   getConnection(String driverName,DbInfoVo dbInfoVo, String url) {
        Connection conn = null;
        try {
            Class.forName(driverName).newInstance();
            conn = DriverManager.getConnection(url, dbInfoVo.getDbUsername(), dbInfoVo.getDbPassword());
        } catch (SQLException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return conn;

    }


    /**
     * 关闭连接
     *
     * @param rSet
     * @param psment
     * @param conn
     * @throws Exception
     */
    public static void closeConnection(ResultSet rSet, Statement psment, Connection conn) {
        try {
            if (rSet != null) {
                rSet.close();
                rSet = null;
            }
            if (psment != null) {
                psment.close();
                psment = null;
            }
            if (conn != null && !conn.isClosed()) {
                conn.close();
                conn = null;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取要比较的数据库详细信息,得到的是一个map
     * 其中key是表名，value是这个表的全部字段详细信息map
     * 表的全部字段详细信息map里，key是字段名，value是这个字段的详细信息
     * 因为可能有多种数据库，用了泛型，T就是MysqlColumnProp,OracleColumnProp这些
     *
     * @param conn
     * @param getTabelNameSQL
     * @param tabColumns
     * @param clazz
     * @param <T>
     * @return
     */
    public static  <T> Map<String, Map<String, T>> getDBInfo(Connection conn,String getTabelNameSQL,String tabColumns,Class<T> clazz) {
        log.info("数据库详细信息获取中。。。。");
        Map<String, Map<String, T>> tableMap = new ConcurrentHashMap<>();
        Statement tableStatement = null;
        ResultSet tableResultSet = null;
        try {
            tableStatement = conn.createStatement();
            tableResultSet = tableStatement.executeQuery(getTabelNameSQL);
            int tableColumnCount = tableResultSet.getMetaData().getColumnCount();
            while (tableResultSet.next()) {
                for (int i = 1; i <= tableColumnCount; i++) {
                    String tableName = tableResultSet.getString(i);
                    ResultSet columnResultSet = null;
                    Statement columnStatement = null;
                    try {
                        columnStatement = conn.createStatement();
                        columnResultSet = columnStatement.executeQuery(getColumnsSQL(tabColumns,tableName));
//                        fixme 这里方法名直接写死了，新增的ColumnProp类不能改这个方法名
                        Method method = clazz.getMethod(DbConstant.METHOD_NAME, ResultSet.class);
//                       getFromResult是静态方法，这里invoke第一个参数固定为null
                        Map<String, T> columnsMap = (Map<String, T>) method.invoke(null, columnResultSet);
                        tableMap.put(tableName, columnsMap);

                    } finally {
                        DbUtil.closeConnection(columnResultSet, columnStatement, null);
                    }
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            DbUtil.closeConnection(tableResultSet, tableStatement, conn);
        }
        return tableMap;
    }
    
}
